package com.yxy.springcloud.framework.unionauth.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.yxy.springcloud.framework.common.base.BusinessException;
import com.yxy.springcloud.framework.common.base.PageDataList;
import com.yxy.springcloud.framework.common.base.RestResponse;
import com.yxy.springcloud.framework.common.redis.RedisUtils;
import com.yxy.springcloud.framework.unionauth.DTO.ConfirmAssignPermissionDto;
import com.yxy.springcloud.framework.unionauth.DTO.RoleCreateDto;
import com.yxy.springcloud.framework.unionauth.DTO.RoleListDto;
import com.yxy.springcloud.framework.unionauth.dao.AppMapper;
import com.yxy.springcloud.framework.unionauth.dao.AppRoleMapper;
import com.yxy.springcloud.framework.unionauth.dao.RoleMapper;
import com.yxy.springcloud.framework.unionauth.model.*;
import com.yxy.springcloud.framework.unionauth.utils.TokenCheckUtil;
import com.yxy.springcloud.framework.unionauth.vo.RoleExtend;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

@Slf4j
@Service
public class RoleService {
  @Autowired
  private TokenCheckUtil tokenCheckUtil;

  @Resource
  private RedisUtils redisUtils;

  @Resource
  private RoleMapper roleMapper;

  @Resource
  private AppRoleMapper appRoleMapper;

  @Resource
  private AppMapper appMapper;

  public PageDataList<RoleExtend> getList(RoleListDto query) {
    List<RoleExtend> resultList = new ArrayList<>();

    PageHelper.startPage(query.getPageNumber(), query.getPageSize());
    PageHelper.orderBy("t1.create_date desc");//排序
    List<Role> dbResult = roleMapper.selectList(query);
    Page<Role> dbResultPage = (Page<Role>) dbResult;

    for (Role dbItem : dbResultPage.getResult()) {
      Long roleId = dbItem.getId();
      RoleExtend roleExtend = new RoleExtend();
      BeanUtils.copyProperties(dbItem, roleExtend);
      List<App> appList = roleMapper.getAppListWithRole(roleId);
      roleExtend.setAppList(appList);
      resultList.add(roleExtend);
    }

    PageDataList<RoleExtend> pageDataList = new PageDataList<>(dbResultPage.getTotal(),
            dbResultPage.getPages(),
            dbResultPage.getPageNum(), dbResultPage.getPageSize());
    pageDataList.setList(resultList);
    return pageDataList;

  }

  public RestResponse getRouterByAppName(String appName) throws BusinessException{
    RestResponse restResponse = new RestResponse(200, "success");
    String routerListStr = redisUtils.get("auth#route#"+ appName);
    if (StringUtils.isEmpty(routerListStr)) {
      log.info("app: {}对应的路由列表为空", appName);
      restResponse.setContent(new ArrayList<>());
      return restResponse;
    }
    restResponse.setContent(JSONArray.parse(routerListStr));
    return restResponse;
  }

  public RestResponse getPermissionListByRole(String roleIdStr, String appName) {
    App appQueryObj = new App();
    appQueryObj.setName(appName);
    App curApp = appMapper.selectOne(appQueryObj);

    RestResponse restResponse = new RestResponse(200, "success");

    Long roleId = Long.parseLong(roleIdStr);
    Long appId = curApp.getId();

    AppRole appRoleQueryObj = new AppRole();
    appRoleQueryObj.setRoleId(roleId);
    appRoleQueryObj.setAppId(appId);
    AppRole curAppRole = appRoleMapper.selectOne(appRoleQueryObj);

    String permissionCodesStr = curAppRole.getPermissionCodes();
    if (StringUtils.isEmpty(permissionCodesStr)) {
      List<String> resultList = new ArrayList<>();
      restResponse.setContent(resultList);
    } else {
      String[] codeList = permissionCodesStr.split(",");
      List resultList = Arrays.asList(codeList);
      restResponse.setContent(resultList);
    }
    return restResponse;
  }

  public Object confirmAssignPermission(ConfirmAssignPermissionDto inputDto) {
    // 查询app详情
    App appQueryObj = new App();
    appQueryObj.setName(inputDto.getAppName());
    App curApp = appMapper.selectOne(appQueryObj);

    AppRole appRoleQueryObj = new AppRole();
    appRoleQueryObj.setRoleId(Long.parseLong(inputDto.getRoleId()));
    appRoleQueryObj.setAppId(curApp.getId());
    AppRole curAppRole = appRoleMapper.selectOne(appRoleQueryObj);

    AppRole appRoleUpdateObj = new AppRole();
    appRoleUpdateObj.setId(curAppRole.getId());
    appRoleUpdateObj.setPermissionCodes(inputDto.getPermissionCodes());
    appRoleMapper.updateByPrimaryKeySelective(appRoleUpdateObj);
    return "角色权限修改成功";
  }

  @Transactional(rollbackFor = Exception.class)
  public Map<String, Object> createOrUpdate(RoleCreateDto inputDto) throws BusinessException{
    // 参数合法校验
    String[] selectedAppIdList = inputDto.getSelectedAppIdList();
    if (selectedAppIdList == null || selectedAppIdList.length == 0) {
      throw new BusinessException(501, "需要至少选择一个app");
    }
    // end
    Map<String, Object> resultMap = new HashMap<>();

    String curUserStr = tokenCheckUtil.getUserInfoByToken();
    AuthAdminUser loginUser = JSON.parseObject(curUserStr, AuthAdminUser.class);

    Long id = inputDto.getId();
    if (id == null) { // insert
      Role insertObj = new Role();
      BeanUtils.copyProperties(inputDto, insertObj);
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, insertObj);
      roleMapper.insertUseGeneratedKeys(insertObj);
      resultMap.put("id", insertObj.getId());
      // 创建角色和app的关系
      this.createAppRoleRelation(inputDto, insertObj.getId(), loginUser);

    } else { // update
      Role updateObj = new Role();
      BeanUtils.copyProperties(inputDto, updateObj);
      updateObj.setId(id);
      updateObj.setUpdateUserId(loginUser.getId());
      updateObj.setUpdateUserName(loginUser.getName());
      updateObj.setUpdateDate(new Date());
      roleMapper.updateByPrimaryKeySelective(updateObj);
      resultMap.put("id", id);
      // 修改角色和app 的关系
      // 删除无用的 app和role的对应关系
      this.deleteAppRoleRelation(inputDto, id);
      // 创建or更新 app_role表
      this.createAppRoleRelation(inputDto, id, loginUser);
    }
    return resultMap;
  }

  // 创建 app和role的对应关系
  private void createAppRoleRelation(RoleCreateDto inputDto, Long roleId, AuthAdminUser loginUser) {
    // 创建角色和app的关系
    List<AppRole> insertObjList = new ArrayList<>();
    String[] appIdList = inputDto.getSelectedAppIdList();
    for (int index = 0;index<appIdList.length;index++) {
      String appIdStr = appIdList[index];
      Long appId = Long.parseLong(appIdStr);
      // 查看 app_role是否存在, 存在则跳过
      AppRole queryObj = new AppRole();
      queryObj.setRoleId(roleId);
      queryObj.setAppId(appId);
      List<AppRole> oldItems = appRoleMapper.select(queryObj);
      if (oldItems.size() > 0) {
        continue;
      }
      // end
      AppRole appRoleInsertObj = new AppRole();
      appRoleInsertObj.setRoleId(roleId);
      appRoleInsertObj.setAppId(appId);
      appRoleInsertObj.setPermissionCodes("");
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, appRoleInsertObj);
      insertObjList.add(appRoleInsertObj);
    }
    if (insertObjList.size() > 0) {
      appRoleMapper.insertList(insertObjList);
    }
  }

  // 删除过时的 app和role的对应关系
  private void deleteAppRoleRelation(RoleCreateDto inputDto, Long roleId) {
    String[] newAppIdList = inputDto.getSelectedAppIdList();
    roleMapper.deleteAppRoleRelation(roleId, newAppIdList);
  }

  @Transactional(rollbackFor = Exception.class)
  public void delete(long id) {
    roleMapper.deleteByPrimaryKey(id);
    // 删除角色与app的对应关系
    AppRole deleteObj= new AppRole();
    deleteObj.setRoleId(id);
    appRoleMapper.delete(deleteObj);
  }

  public RestResponse getAppListByRole(String roleId) {
    List<App> appListWithRole = roleMapper.getAppListWithRole(Long.parseLong(roleId));
    RestResponse restResponse = new RestResponse(200, "success");
    restResponse.setContent(appListWithRole);
    return restResponse;
  }
}
